home *** CD-ROM | disk | FTP | other *** search
/ PC go! 2017 October / PCgo 10-2017 CD-ROM Germany.iso / nw.pak / Unnamed File 000192.txt < prev    next >
Encoding:
Text File  |  2015-07-29  |  13.9 KB  |  472 lines

  1.  
  2.  
  3.     Polymer('core-selector', {
  4.  
  5.       /**
  6.        * Gets or sets the selected element.  Default to use the index
  7.        * of the item element.
  8.        *
  9.        * If you want a specific attribute value of the element to be
  10.        * used instead of index, set "valueattr" to that attribute name.
  11.        *
  12.        * Example:
  13.        *
  14.        *     <core-selector valueattr="label" selected="foo">
  15.        *       <div label="foo"></div>
  16.        *       <div label="bar"></div>
  17.        *       <div label="zot"></div>
  18.        *     </core-selector>
  19.        *
  20.        * In multi-selection this should be an array of values.
  21.        *
  22.        * Example:
  23.        *
  24.        *     <core-selector id="selector" valueattr="label" multi>
  25.        *       <div label="foo"></div>
  26.        *       <div label="bar"></div>
  27.        *       <div label="zot"></div>
  28.        *     </core-selector>
  29.        *
  30.        *     this.$.selector.selected = ['foo', 'zot'];
  31.        *
  32.        * @attribute selected
  33.        * @type Object
  34.        * @default null
  35.        */
  36.       selected: null,
  37.  
  38.       /**
  39.        * If true, multiple selections are allowed.
  40.        *
  41.        * @attribute multi
  42.        * @type boolean
  43.        * @default false
  44.        */
  45.       multi: false,
  46.  
  47.       /**
  48.        * Specifies the attribute to be used for "selected" attribute.
  49.        *
  50.        * @attribute valueattr
  51.        * @type string
  52.        * @default 'name'
  53.        */
  54.       valueattr: 'name',
  55.  
  56.       /**
  57.        * Specifies the CSS class to be used to add to the selected element.
  58.        * 
  59.        * @attribute selectedClass
  60.        * @type string
  61.        * @default 'core-selected'
  62.        */
  63.       selectedClass: 'core-selected',
  64.  
  65.       /**
  66.        * Specifies the property to be used to set on the selected element
  67.        * to indicate its active state.
  68.        *
  69.        * @attribute selectedProperty
  70.        * @type string
  71.        * @default ''
  72.        */
  73.       selectedProperty: '',
  74.  
  75.       /**
  76.        * Specifies the attribute to set on the selected element to indicate
  77.        * its active state.
  78.        *
  79.        * @attribute selectedAttribute
  80.        * @type string
  81.        * @default 'active'
  82.        */
  83.       selectedAttribute: 'active',
  84.  
  85.       /**
  86.        * Returns the currently selected element. In multi-selection this returns
  87.        * an array of selected elements.
  88.        * Note that you should not use this to set the selection. Instead use
  89.        * `selected`.
  90.        * 
  91.        * @attribute selectedItem
  92.        * @type Object
  93.        * @default null
  94.        */
  95.       selectedItem: null,
  96.  
  97.       /**
  98.        * In single selection, this returns the model associated with the
  99.        * selected element.
  100.        * Note that you should not use this to set the selection. Instead use 
  101.        * `selected`.
  102.        * 
  103.        * @attribute selectedModel
  104.        * @type Object
  105.        * @default null
  106.        */
  107.       selectedModel: null,
  108.  
  109.       /**
  110.        * In single selection, this returns the selected index.
  111.        * Note that you should not use this to set the selection. Instead use
  112.        * `selected`.
  113.        *
  114.        * @attribute selectedIndex
  115.        * @type number
  116.        * @default -1
  117.        */
  118.       selectedIndex: -1,
  119.  
  120.       /**
  121.        * Nodes with local name that are in the list will not be included 
  122.        * in the selection items.  In the following example, `items` returns four
  123.        * `core-item`'s and doesn't include `h3` and `hr`.
  124.        *
  125.        *     <core-selector excludedLocalNames="h3 hr">
  126.        *       <h3>Header</h3>
  127.        *       <core-item>Item1</core-item>
  128.        *       <core-item>Item2</core-item>
  129.        *       <hr>
  130.        *       <core-item>Item3</core-item>
  131.        *       <core-item>Item4</core-item>
  132.        *     </core-selector>
  133.        *
  134.        * @attribute excludedLocalNames
  135.        * @type string
  136.        * @default ''
  137.        */
  138.       excludedLocalNames: '',
  139.  
  140.       /**
  141.        * The target element that contains items.  If this is not set 
  142.        * core-selector is the container.
  143.        * 
  144.        * @attribute target
  145.        * @type Object
  146.        * @default null
  147.        */
  148.       target: null,
  149.  
  150.       /**
  151.        * This can be used to query nodes from the target node to be used for 
  152.        * selection items.  Note this only works if `target` is set
  153.        * and is not `core-selector` itself.
  154.        *
  155.        * Example:
  156.        *
  157.        *     <core-selector target="{{$.myForm}}" itemsSelector="input[type=radio]"></core-selector>
  158.        *     <form id="myForm">
  159.        *       <label><input type="radio" name="color" value="red"> Red</label> <br>
  160.        *       <label><input type="radio" name="color" value="green"> Green</label> <br>
  161.        *       <label><input type="radio" name="color" value="blue"> Blue</label> <br>
  162.        *       <p>color = {{color}}</p>
  163.        *     </form>
  164.        * 
  165.        * @attribute itemsSelector
  166.        * @type string
  167.        * @default ''
  168.        */
  169.       itemsSelector: '',
  170.  
  171.       /**
  172.        * The event that would be fired from the item element to indicate
  173.        * it is being selected.
  174.        *
  175.        * @attribute activateEvent
  176.        * @type string
  177.        * @default 'tap'
  178.        */
  179.       activateEvent: 'tap',
  180.  
  181.       /**
  182.        * Set this to true to disallow changing the selection via the
  183.        * `activateEvent`.
  184.        *
  185.        * @attribute notap
  186.        * @type boolean
  187.        * @default false
  188.        */
  189.       notap: false,
  190.  
  191.       defaultExcludedLocalNames: 'template',
  192.       
  193.       observe: {
  194.         'selected multi': 'selectedChanged'
  195.       },
  196.  
  197.       ready: function() {
  198.         this.activateListener = this.activateHandler.bind(this);
  199.         this.itemFilter = this.filterItem.bind(this);
  200.         this.excludedLocalNamesChanged();
  201.         this.observer = new MutationObserver(this.updateSelected.bind(this));
  202.         if (!this.target) {
  203.           this.target = this;
  204.         }
  205.       },
  206.  
  207.       /**
  208.        * Returns an array of all items.
  209.        *
  210.        * @property items
  211.        */
  212.       get items() {
  213.         if (!this.target) {
  214.           return [];
  215.         }
  216.         var nodes = this.target !== this ? (this.itemsSelector ? 
  217.             this.target.querySelectorAll(this.itemsSelector) : 
  218.                 this.target.children) : this.$.items.getDistributedNodes();
  219.         return Array.prototype.filter.call(nodes, this.itemFilter);
  220.       },
  221.  
  222.       filterItem: function(node) {
  223.         return !this._excludedNames[node.localName];
  224.       },
  225.  
  226.       excludedLocalNamesChanged: function() {
  227.         this._excludedNames = {};
  228.         var s = this.defaultExcludedLocalNames;
  229.         if (this.excludedLocalNames) {
  230.           s += ' ' + this.excludedLocalNames;
  231.         }
  232.         s.split(/\s+/g).forEach(function(n) {
  233.           this._excludedNames[n] = 1;
  234.         }, this);
  235.       },
  236.  
  237.       targetChanged: function(old) {
  238.         if (old) {
  239.           this.removeListener(old);
  240.           this.observer.disconnect();
  241.           this.clearSelection();
  242.         }
  243.         if (this.target) {
  244.           this.addListener(this.target);
  245.           this.observer.observe(this.target, {childList: true});
  246.           this.updateSelected();
  247.         }
  248.       },
  249.  
  250.       addListener: function(node) {
  251.         Polymer.addEventListener(node, this.activateEvent, this.activateListener);
  252.       },
  253.  
  254.       removeListener: function(node) {
  255.         Polymer.removeEventListener(node, this.activateEvent, this.activateListener);
  256.       },
  257.  
  258.       /**
  259.        * Returns the selected item(s). If the `multi` property is true,
  260.        * this will return an array, otherwise it will return 
  261.        * the selected item or undefined if there is no selection.
  262.        */
  263.       get selection() {
  264.         return this.$.selection.getSelection();
  265.       },
  266.  
  267.       selectedChanged: function() {
  268.         // TODO(ffu): Right now this is the only way to know that the `selected`
  269.         // is an array and was mutated, as opposed to newly assigned.
  270.         if (arguments.length === 1) {
  271.           this.processSplices(arguments[0]);
  272.         } else {
  273.           this.updateSelected();
  274.         }
  275.       },
  276.       
  277.       updateSelected: function() {
  278.         this.validateSelected();
  279.         if (this.multi) {
  280.           this.clearSelection(this.selected)
  281.           this.selected && this.selected.forEach(function(s) {
  282.             this.setValueSelected(s, true)
  283.           }, this);
  284.         } else {
  285.           this.valueToSelection(this.selected);
  286.         }
  287.       },
  288.  
  289.       validateSelected: function() {
  290.         // convert to an array for multi-selection
  291.         if (this.multi && !Array.isArray(this.selected) && 
  292.             this.selected != null) {
  293.           this.selected = [this.selected];
  294.         // use the first selected in the array for single-selection
  295.         } else if (!this.multi && Array.isArray(this.selected)) {
  296.           var s = this.selected[0];
  297.           this.clearSelection([s]);
  298.           this.selected = s;
  299.         }
  300.       },
  301.       
  302.       processSplices: function(splices) {
  303.         for (var i = 0, splice; splice = splices[i]; i++) {
  304.           for (var j = 0; j < splice.removed.length; j++) {
  305.             this.setValueSelected(splice.removed[j], false);
  306.           }
  307.           for (var j = 0; j < splice.addedCount; j++) {
  308.             this.setValueSelected(this.selected[splice.index + j], true);
  309.           }
  310.         }
  311.       },
  312.  
  313.       clearSelection: function(excludes) {
  314.         this.$.selection.selection.slice().forEach(function(item) {
  315.           var v = this.valueForNode(item) || this.items.indexOf(item);
  316.           if (!excludes || excludes.indexOf(v) < 0) {
  317.             this.$.selection.setItemSelected(item, false);
  318.           }
  319.         }, this);
  320.       },
  321.  
  322.       valueToSelection: function(value) {
  323.         var item = this.valueToItem(value);
  324.         this.$.selection.select(item);
  325.       },
  326.       
  327.       setValueSelected: function(value, isSelected) {
  328.         var item = this.valueToItem(value);
  329.         if (isSelected ^ this.$.selection.isSelected(item)) {
  330.           this.$.selection.setItemSelected(item, isSelected);
  331.         }
  332.       },
  333.  
  334.       updateSelectedItem: function() {
  335.         this.selectedItem = this.selection;
  336.       },
  337.  
  338.       selectedItemChanged: function() {
  339.         if (this.selectedItem) {
  340.           var t = this.selectedItem.templateInstance;
  341.           this.selectedModel = t ? t.model : undefined;
  342.         } else {
  343.           this.selectedModel = null;
  344.         }
  345.         this.selectedIndex = this.selectedItem ? 
  346.             parseInt(this.valueToIndex(this.selected)) : -1;
  347.       },
  348.       
  349.       valueToItem: function(value) {
  350.         return (value === null || value === undefined) ? 
  351.             null : this.items[this.valueToIndex(value)];
  352.       },
  353.  
  354.       valueToIndex: function(value) {
  355.         // find an item with value == value and return it's index
  356.         for (var i=0, items=this.items, c; (c=items[i]); i++) {
  357.           if (this.valueForNode(c) == value) {
  358.             return i;
  359.           }
  360.         }
  361.         // if no item found, the value itself is probably the index
  362.         return value;
  363.       },
  364.  
  365.       valueForNode: function(node) {
  366.         return node[this.valueattr] || node.getAttribute(this.valueattr);
  367.       },
  368.  
  369.       // events fired from <core-selection> object
  370.       selectionSelect: function(e, detail) {
  371.         this.updateSelectedItem();
  372.         if (detail.item) {
  373.           this.applySelection(detail.item, detail.isSelected);
  374.         }
  375.       },
  376.  
  377.       applySelection: function(item, isSelected) {
  378.         if (this.selectedClass) {
  379.           item.classList.toggle(this.selectedClass, isSelected);
  380.         }
  381.         if (this.selectedProperty) {
  382.           item[this.selectedProperty] = isSelected;
  383.         }
  384.         if (this.selectedAttribute && item.setAttribute) {
  385.           if (isSelected) {
  386.             item.setAttribute(this.selectedAttribute, '');
  387.           } else {
  388.             item.removeAttribute(this.selectedAttribute);
  389.           }
  390.         }
  391.       },
  392.  
  393.       // event fired from host
  394.       activateHandler: function(e) {
  395.         if (!this.notap) {
  396.           var i = this.findDistributedTarget(e.target, this.items);
  397.           if (i >= 0) {
  398.             var item = this.items[i];
  399.             var s = this.valueForNode(item) || i;
  400.             if (this.multi) {
  401.               if (this.selected) {
  402.                 this.addRemoveSelected(s);
  403.               } else {
  404.                 this.selected = [s];
  405.               }
  406.             } else {
  407.               this.selected = s;
  408.             }
  409.             this.asyncFire('core-activate', {item: item});
  410.           }
  411.         }
  412.       },
  413.  
  414.       addRemoveSelected: function(value) {
  415.         var i = this.selected.indexOf(value);
  416.         if (i >= 0) {
  417.           this.selected.splice(i, 1);
  418.         } else {
  419.           this.selected.push(value);
  420.         }
  421.       },
  422.  
  423.       findDistributedTarget: function(target, nodes) {
  424.         // find first ancestor of target (including itself) that
  425.         // is in nodes, if any
  426.         while (target && target != this) {
  427.           var i = Array.prototype.indexOf.call(nodes, target);
  428.           if (i >= 0) {
  429.             return i;
  430.           }
  431.           target = target.parentNode;
  432.         }
  433.       },
  434.       
  435.       selectIndex: function(index) {
  436.         var item = this.items[index];
  437.         if (item) {
  438.           this.selected = this.valueForNode(item) || index;
  439.           return item;
  440.         }
  441.       },
  442.       
  443.       /**
  444.        * Selects the previous item. This should be used in single selection only.
  445.        *
  446.        * @method selectPrevious
  447.        * @param {boolean} wrapped if true and it is already at the first item,
  448.        *                  wrap to the end
  449.        * @returns the previous item or undefined if there is none
  450.        */
  451.       selectPrevious: function(wrapped) {
  452.         var i = wrapped && !this.selectedIndex ? 
  453.             this.items.length - 1 : this.selectedIndex - 1;
  454.         return this.selectIndex(i);
  455.       },
  456.       
  457.       /**
  458.        * Selects the next item.  This should be used in single selection only.
  459.        *
  460.        * @method selectNext
  461.        * @param {boolean} wrapped if true and it is already at the last item,
  462.        *                  wrap to the front
  463.        * @returns the next item or undefined if there is none
  464.        */
  465.       selectNext: function(wrapped) {
  466.         var i = wrapped && this.selectedIndex >= this.items.length - 1 ? 
  467.             0 : this.selectedIndex + 1;
  468.         return this.selectIndex(i);
  469.       }
  470.       
  471.     });
  472.